package org.zhaya.core;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.zhaya.annotation.XxlRegister;
import org.zhaya.model.XxlJobGroup;
import org.zhaya.model.XxlJobInfo;
import org.zhaya.service.JobGroupService;
import org.zhaya.service.JobInfoService;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Component
public class XxlJobAutoRegister implements ApplicationListener<ApplicationReadyEvent>,
    ApplicationContextAware {

    private static final Log log = LogFactory.get();

    private ApplicationContext applicationContext;

    @Value("${xxl.job.enabled}")
    private Boolean enabled;

    @Autowired
    private JobGroupService jobGroupService;

    @Autowired
    private JobInfoService jobInfoService;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        if (enabled) {
            //注册执行器
            addJobGroup();
            //注册任务
            addJobInfo();
        }
    }

    //自动注册执行器
    private void addJobGroup() {
        //校验执行器是否存在
        if (jobGroupService.preciselyCheck())
            return;
        //注册执行器
        if (jobGroupService.autoRegisterGroup())
            log.info("auto register xxl-job group success!");
    }

    private void addJobInfo() {
        List<XxlJobGroup> jobGroups = jobGroupService.getJobGroup();
        XxlJobGroup xxlJobGroup = jobGroups.get(0);

        String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanDefinitionName);

            Map<Method, XxlJob> annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
                new MethodIntrospector.MetadataLookup<XxlJob>() {
                    @Override
                    public XxlJob inspect(Method method) {
                        return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
                    }
                });
            for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
                Method executeMethod = methodXxlJobEntry.getKey();
                XxlJob xxlJob = methodXxlJobEntry.getValue();
                //查找执行器下的任务
                List<XxlJobInfo> jobInfo = jobInfoService.getJobInfo(xxlJobGroup.getId(), xxlJob.value());

                //自动注册
                if (executeMethod.isAnnotationPresent(XxlRegister.class)) {
                    XxlRegister xxlRegister = executeMethod.getAnnotation(XxlRegister.class);
                    XxlJobInfo newXxlJobInfo =createXxlJobInfo(xxlJobGroup , xxlJob, xxlRegister);
                    if (!jobInfo.isEmpty()) {
                        //查找旧的任务
                        Optional<XxlJobInfo> oldJob = jobInfo.stream()
                            .filter(xxlJobInfo -> xxlJobInfo.getExecutorHandler().equals(xxlJob.value()))
                            .findFirst();
                        if (oldJob.isPresent()) {
                            //任务存在，比对执行计划是否一致，不一致进行更新
                            XxlJobInfo oldXxlJobInfo = oldJob.get();
                            if (!oldXxlJobInfo.getScheduleConf().equals(newXxlJobInfo.getScheduleConf())) {
                                oldXxlJobInfo.setScheduleConf(newXxlJobInfo.getScheduleConf());
                                jobInfoService.updateJobInfo(oldXxlJobInfo);
                            }

                        }
                    } else {
                        //任务不存在，直接运行
                        jobInfoService.addJobInfo(newXxlJobInfo);
                    }
                }
            }
        }
    }

    private XxlJobInfo createXxlJobInfo(XxlJobGroup xxlJobGroup, XxlJob xxlJob, XxlRegister xxlRegister) {
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setJobGroup(xxlJobGroup.getId());
        xxlJobInfo.setJobDesc(xxlRegister.jobDesc());
        xxlJobInfo.setAuthor(xxlRegister.author());
        xxlJobInfo.setScheduleType("CRON");
        xxlJobInfo.setScheduleConf(xxlRegister.cron());
        xxlJobInfo.setGlueType("BEAN");
        xxlJobInfo.setExecutorHandler(xxlJob.value());
        xxlJobInfo.setExecutorRouteStrategy(xxlRegister.executorRouteStrategy());
        xxlJobInfo.setMisfireStrategy("DO_NOTHING");
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
        xxlJobInfo.setExecutorTimeout(0);
        xxlJobInfo.setExecutorFailRetryCount(0);
        xxlJobInfo.setGlueRemark("GLUE代码初始化");
        xxlJobInfo.setTriggerStatus(xxlRegister.triggerStatus());

        return xxlJobInfo;
    }

}
